home *** CD-ROM | disk | FTP | other *** search
/ ASME's Mechanical Engine…ing Toolkit 1997 December / ASME's Mechanical Engineering Toolkit 1997 December.iso / c_lang / sc.zoo / interp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-06-03  |  30.4 KB  |  1,419 lines

  1. /*    SC    A Spreadsheet Calculator
  2.  *        Expression interpreter and assorted support routines.
  3.  *
  4.  *        original by James Gosling, September 1982
  5.  *        modified by Mark Weiser and Bruce Israel, 
  6.  *            University of Maryland
  7.  *
  8.  *              More mods Robert Bond, 12/86
  9.  */
  10.  
  11. #include <math.h>
  12. #include <signal.h>
  13. #include <setjmp.h>
  14. #include <stdio.h>
  15.  
  16. #ifdef BSD42
  17. #include <strings.h>
  18. #include <sys/time.h>
  19. #else
  20. #include <time.h>
  21. #ifndef SYSIII
  22. #include <string.h>
  23. #endif
  24. #endif
  25.  
  26. #include <curses.h>
  27. #include "sc.h"
  28. #define DEFCOLDELIM ':'
  29.  
  30. extern char curfile[];
  31.  
  32. jmp_buf fpe_save;
  33. int    exprerr;    /* Set by eval() and seval() if expression errors */
  34.  
  35. #ifdef SYSV3
  36. void exit();
  37. #endif
  38. #define PI (double)3.14159265358979323846
  39. #define dtr(x) ((x)*(PI/(double)180.0))
  40. #define rtd(x) ((x)*(180.0/(double)PI))
  41.  
  42. double
  43. dosum(minr, minc, maxr, maxc)
  44. int minr, minc, maxr, maxc;
  45. {
  46.     double v;
  47.     register r,c;
  48.     register struct ent *p;
  49.  
  50.     v = 0;
  51.     for (r = minr; r<=maxr; r++)
  52.     for (c = minc; c<=maxc; c++)
  53.         if ((p = tbl[r][c]) && p->flags&is_valid)
  54.         v += p->v;
  55.     return v;
  56. }
  57.  
  58. double
  59. doprod(minr, minc, maxr, maxc)
  60. int minr, minc, maxr, maxc;
  61. {
  62.     double v;
  63.     register r,c;
  64.     register struct ent *p;
  65.  
  66.     v = 1;
  67.     for (r = minr; r<=maxr; r++)
  68.     for (c = minc; c<=maxc; c++)
  69.         if ((p = tbl[r][c]) && p->flags&is_valid)
  70.         v *= p->v;
  71.     return v;
  72. }
  73.  
  74. double
  75. doavg(minr, minc, maxr, maxc)
  76. int minr, minc, maxr, maxc;
  77. {
  78.     double v;
  79.     register r,c,count;
  80.     register struct ent *p;
  81.  
  82.     v = 0;
  83.     count = 0;
  84.     for (r = minr; r<=maxr; r++)
  85.     for (c = minc; c<=maxc; c++)
  86.         if ((p = tbl[r][c]) && p->flags&is_valid) {
  87.         v += p->v;
  88.         count++;
  89.         }
  90.  
  91.     if (count == 0) 
  92.     return ((double) 0);
  93.  
  94.     return (v / (double)count);
  95. }
  96.  
  97. double
  98. dostddev(minr, minc, maxr, maxc)
  99. int minr, minc, maxr, maxc;
  100. {
  101.     double lp, rp, v, nd;
  102.     register r,c,n;
  103.     register struct ent *p;
  104.  
  105.     n = 0;
  106.     lp = 0;
  107.     rp = 0;
  108.     for (r = minr; r<=maxr; r++)
  109.     for (c = minc; c<=maxc; c++)
  110.         if ((p = tbl[r][c]) && p->flags&is_valid) {
  111.         v = p->v;
  112.         lp += v*v;
  113.         rp += v;
  114.         n++;
  115.         }
  116.  
  117.     if ((n == 0) || (n == 1)) 
  118.     return ((double) 0);
  119.     nd = (double)n;
  120.     return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
  121. }
  122.  
  123. double
  124. domax(minr, minc, maxr, maxc)
  125. int minr, minc, maxr, maxc;
  126. {
  127.     double v;
  128.     register r,c,count;
  129.     register struct ent *p;
  130.  
  131.     count = 0;
  132.     for (r = minr; r<=maxr; r++)
  133.     for (c = minc; c<=maxc; c++)
  134.         if ((p = tbl[r][c]) && p->flags&is_valid) {
  135.         if (!count) {
  136.             v = p->v;
  137.             count++;
  138.         } else if (p->v > v)
  139.             v = p->v;
  140.         }
  141.  
  142.     if (count == 0) 
  143.     return ((double) 0);
  144.  
  145.     return (v);
  146. }
  147.  
  148. double
  149. domin(minr, minc, maxr, maxc)
  150. int minr, minc, maxr, maxc;
  151. {
  152.     double v;
  153.     register r,c,count;
  154.     register struct ent *p;
  155.  
  156.     count = 0;
  157.     for (r = minr; r<=maxr; r++)
  158.     for (c = minc; c<=maxc; c++)
  159.         if ((p = tbl[r][c]) && p->flags&is_valid) {
  160.         if (!count) {
  161.             v = p->v;
  162.             count++;
  163.         } else if (p->v < v)
  164.             v = p->v;
  165.         }
  166.  
  167.     if (count == 0) 
  168.     return ((double) 0);
  169.  
  170.     return (v);
  171. }
  172.  
  173. double
  174. dotime(which, when)
  175. int which;
  176. double when;
  177. {
  178.     long time();
  179.  
  180.     static long t_cache;
  181.     static struct tm *tp;
  182.     long tloc;
  183.  
  184.     if (which == NOW) 
  185.         return (double)time((long *)0);
  186.  
  187.     tloc = (long)when;
  188.  
  189.     if (tloc != t_cache) {
  190.         tp = localtime(&tloc);
  191.         tp->tm_mon += 1;
  192.         tp->tm_year += 1900;
  193.         t_cache = tloc;
  194.     }
  195.  
  196.     switch (which) {
  197.         case HOUR: return((double)(tp->tm_hour));
  198.         case MINUTE: return((double)(tp->tm_min));
  199.         case SECOND: return((double)(tp->tm_sec));
  200.         case MONTH: return((double)(tp->tm_mon));
  201.         case DAY: return((double)(tp->tm_mday));
  202.         case YEAR: return((double)(tp->tm_year));
  203.     }
  204.     /* Safety net */
  205.     return (0.0);
  206. }
  207.  
  208. double
  209. doston(s)
  210. char *s;
  211. {
  212.     char *strtof();
  213.     double v;
  214.  
  215.     if (!s)
  216.     return((double)0.0);
  217.  
  218.     (void)strtof(s, &v);
  219.     xfree(s);
  220.     return(v);
  221. }
  222.  
  223. double
  224. doeqs(s1, s2)
  225. char *s1, *s2;
  226. {
  227.     double v;
  228.  
  229.     if (strcmp(s1, s2) == 0)
  230.     v = 1.0;
  231.     else
  232.     v = 0.0;
  233.  
  234.     if (s1)
  235.         xfree(s1);
  236.  
  237.     if (s2)
  238.         xfree(s2);
  239.  
  240.     return(v);
  241. }
  242.  
  243. double 
  244. eval(e)
  245. register struct enode *e;
  246. {
  247.     if (e==0) return 0;
  248.     switch (e->op) {
  249.     case '+':    return (eval(e->e.o.left) + eval(e->e.o.right));
  250.     case '-':    return (eval(e->e.o.left) - eval(e->e.o.right));
  251.     case '*':    return (eval(e->e.o.left) * eval(e->e.o.right));
  252.     case '/':     {    double denom = eval (e->e.o.right);
  253.             return denom ? eval(e->e.o.left) / denom : 0; }
  254.     case '^':    return (pow(eval(e->e.o.left), eval(e->e.o.right)));
  255.     case '<':    return (eval(e->e.o.left) < eval(e->e.o.right));
  256.     case '=':    return (eval(e->e.o.left) == eval(e->e.o.right));
  257.     case '>':    return (eval(e->e.o.left) > eval(e->e.o.right));
  258.     case '&':    return (eval(e->e.o.left) && eval(e->e.o.right));
  259.     case '|':    return (eval(e->e.o.left) || eval(e->e.o.right));
  260.     case '?':    return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
  261.                         : eval(e->e.o.right->e.o.right);
  262.     case 'm':    return (-eval(e->e.o.right));
  263.     case 'f':    return (eval(e->e.o.right));
  264.     case '~':    return (eval(e->e.o.right) == 0.0);
  265.     case 'k':    return (e->e.k);
  266.     case 'v':    return (e->e.v.vp->v);
  267.     case O_REDUCE('+'):
  268.      case O_REDUCE('*'):
  269.      case O_REDUCE('a'):
  270.      case O_REDUCE('s'):
  271.     case O_REDUCE(MAX):
  272.     case O_REDUCE(MIN):
  273.         {    register r,c;
  274.         register maxr, maxc;
  275.         register minr, minc;
  276.         maxr = e->e.r.right.vp -> row;
  277.         maxc = e->e.r.right.vp -> col;
  278.         minr = e->e.r.left.vp -> row;
  279.         minc = e->e.r.left.vp -> col;
  280.         if (minr>maxr) r = maxr, maxr = minr, minr = r;
  281.         if (minc>maxc) c = maxc, maxc = minc, minc = c;
  282.             switch (e->op) {
  283.                 case O_REDUCE('+'): return dosum(minr, minc, maxr, maxc);
  284.                  case O_REDUCE('*'): return doprod(minr, minc, maxr, maxc);
  285.                  case O_REDUCE('a'): return doavg(minr, minc, maxr, maxc);
  286.                  case O_REDUCE('s'): return dostddev(minr, minc, maxr, maxc);
  287.                  case O_REDUCE(MAX): return domax(minr, minc, maxr, maxc);
  288.                  case O_REDUCE(MIN): return domin(minr, minc, maxr, maxc);
  289.         }
  290.         }
  291.     case ACOS:     return (acos(eval(e->e.o.right)));
  292.     case ASIN:     return (asin(eval(e->e.o.right)));
  293.     case ATAN:     return (atan(eval(e->e.o.right)));
  294.     case CEIL:     return (ceil(eval(e->e.o.right)));
  295.     case COS:     return (cos(eval(e->e.o.right)));
  296.     case EXP:     return (exp(eval(e->e.o.right)));
  297.     case FABS:     return (fabs(eval(e->e.o.right)));
  298.     case FLOOR:     return (floor(eval(e->e.o.right)));
  299.     case HYPOT:     return (hypot(eval(e->e.o.left), eval(e->e.o.right)));
  300.     case LOG:     { double arg = eval(e->e.o.right);
  301.                return arg ? log(arg) : 0; }
  302.     case LOG10:     { double arg = eval(e->e.o.right);
  303.                return arg ? log10(arg) : 0; }
  304.     case POW:     return (pow(eval(e->e.o.left), eval(e->e.o.right)));
  305.     case SIN:     return (sin(eval(e->e.o.right)));
  306.     case SQRT:     return (sqrt(eval(e->e.o.right)));
  307.     case TAN:     return (tan(eval(e->e.o.right)));
  308.     case DTR:     return (dtr(eval(e->e.o.right)));
  309.     case RTD:     return (rtd(eval(e->e.o.right)));
  310.     case RND:     {
  311.                 double temp;
  312.                 temp = eval(e->e.o.right);
  313.                 return(temp-floor(temp) < 0.5 ?
  314.                          floor(temp) : ceil(temp));
  315.              }
  316.     case HOUR:     return (dotime(HOUR, eval(e->e.o.right)));
  317.     case MINUTE:     return (dotime(MINUTE, eval(e->e.o.right)));
  318.     case SECOND:     return (dotime(SECOND, eval(e->e.o.right)));
  319.     case MONTH:     return (dotime(MONTH, eval(e->e.o.right)));
  320.     case DAY:     return (dotime(DAY, eval(e->e.o.right)));
  321.     case YEAR:     return (dotime(YEAR, eval(e->e.o.right)));
  322.     case NOW:     return (dotime(NOW, (double)0.0));
  323.     case STON:     return (doston(seval(e->e.o.right)));
  324.     case EQS:        return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
  325.     default:     error("Illegal Numeric Expression");
  326.              exprerr = 1;
  327.              return((double)0.0);
  328.     }
  329. }
  330.  
  331. /* 
  332.  * Rules for string functions:
  333.  * Take string arguments which they xfree.
  334.  * All returned strings are assumed to be xalloced.
  335.  */
  336.  
  337. char *
  338. docat(s1, s2)
  339. register char *s1, *s2;
  340. {
  341.     register char *p;
  342.  
  343.     p = xmalloc((unsigned)(strlen(s1)+strlen(s2)+1));
  344.     (void) strcpy(p, s1);
  345.     (void) strcat(p, s2);
  346.     if (s1)
  347.         xfree(s1);
  348.     if (s2)
  349.         xfree(s2);
  350.     return(p);
  351. }
  352.  
  353. char *
  354. dodate(tloc)
  355. long tloc;
  356. {
  357.     char *tp;
  358.     char *p;
  359.  
  360.     tp = ctime(&tloc);
  361.     tp[24] = 0;
  362.     p = xmalloc((unsigned)25);
  363.     (void) strcpy(p, tp);
  364.     return(p);
  365. }
  366.  
  367. char *
  368. dofmt(fmtstr, v)
  369. char *fmtstr;
  370. double v;
  371. {
  372.     char buff[1024];
  373.     char *p;
  374.  
  375.     if (!fmtstr)
  376.     return(0);
  377.     (void)sprintf(buff, fmtstr, v);
  378.     p = xmalloc((unsigned)(strlen(buff)+1));
  379.     (void) strcpy(p, buff);
  380.     xfree(fmtstr);
  381.     return(p);
  382. }
  383.  
  384. char *
  385. dosubstr(s, v1, v2)
  386. char *s;
  387. register int v1,v2;
  388. {
  389.     register char *s1, *s2;
  390.     char *p;
  391.  
  392.     if (!s)
  393.     return(0);
  394.  
  395.     if (v1 < 0 || v2 < v1 || strlen(s) <= v2 ) {
  396.     xfree(s);
  397.     p = xmalloc((unsigned)1);
  398.     p[0] = 0;
  399.     return(p);
  400.     }
  401.     s2 = p = xmalloc((unsigned)(v2-v1+2));
  402.     s1 = &s[v1];
  403.     for(; v1 <= v2; s1++, s2++, v1++)
  404.     *s2 = *s1;
  405.     *s2 = 0;
  406.     xfree(s);
  407.     return(p);
  408. }
  409.  
  410. char *
  411. seval(se)
  412. register struct enode *se;
  413. {
  414.     register char *p;
  415.  
  416.     if (se==0) return 0;
  417.     switch (se->op) {
  418.     case O_SCONST: p = xmalloc((unsigned)(strlen(se->e.s)+1));
  419.              (void) strcpy(p, se->e.s);
  420.              return(p);
  421.     case O_VAR:    {
  422.             struct ent *ep;
  423.  
  424.             ep = se->e.v.vp;
  425.             p = xmalloc((unsigned)(strlen(ep->label)+1));
  426.             (void) strcpy(p, ep->label);
  427.             return(p);
  428.              }
  429.     case '#':    return(docat(seval(se->e.o.left), seval(se->e.o.right)));
  430.     case 'f':    return(seval(se->e.o.right));
  431.     case '?':    return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
  432.                          : seval(se->e.o.right->e.o.right));
  433.     case DATE:   return(dodate((long)(eval(se->e.o.right))));
  434.     case FMT:    return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
  435.     case SUBSTR: return(dosubstr(seval(se->e.o.left),
  436.                 (int)eval(se->e.o.right->e.o.left) - 1,
  437.                 (int)eval(se->e.o.right->e.o.right) - 1));
  438.     default:
  439.              error("Illegal String Expression");
  440.              exprerr = 1;
  441.              return(0);
  442.     }
  443. }
  444.  
  445. #define MAXPROP 7
  446.  
  447. EvalAll () {
  448.     int repct = 0;
  449.  
  450.     while (RealEvalAll() && (repct++ <= MAXPROP));
  451. }
  452.  
  453.  
  454. #ifdef SYSV3
  455. void
  456. #endif
  457. eval_fpe() /* Trap for FPE errors in eval */
  458. {
  459.     longjmp(fpe_save, 1);
  460. }
  461.  
  462. int 
  463. RealEvalAll () {
  464.     register i,j;
  465.     int chgct = 0;
  466.     register struct ent *p;
  467. #ifdef SYSV3
  468.     void quit();
  469. #else
  470.     int quit();
  471. #endif
  472.  
  473.     (void) signal(SIGFPE, eval_fpe);
  474.     for (i=0; i<=maxrow; i++)
  475.     for (j=0; j<=maxcol; j++)
  476.         if ((p=tbl[i][j]) && p->expr) {
  477.         if (p->flags & is_strexpr) {
  478.             char *v;
  479.             if (setjmp(fpe_save)) {
  480.             error("Floating point exception %s", v_name(i,j));
  481.             v = "";
  482.             } else {
  483.                 v = seval(p->expr);
  484.             }
  485.             if (strcmp(v, p->label) != 0) {
  486.             chgct++;
  487.                 p->flags |= is_changed;
  488.             }
  489.             if(p->label)
  490.             xfree(p->label);
  491.             p->label = v;
  492.         } else {
  493.             double v;
  494.             if (setjmp(fpe_save)) {
  495.             error("Floating point exception %s", v_name(i,j));
  496.             v = 0.0;
  497.             } else {
  498.                 v = eval (p->expr);
  499.             }
  500.             if (v != p->v) {
  501.             p->v = v; chgct++;
  502.             p->flags |= (is_changed|is_valid);
  503.             }
  504.         }
  505.         }
  506.     (void) signal(SIGFPE, quit);
  507.     return(chgct);
  508. }
  509.  
  510. struct enode *
  511. new(op, a1, a2)
  512. struct enode *a1, *a2;
  513. {
  514.     register struct enode *p;
  515.     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  516.     p->op = op;
  517.     p->e.o.left = a1;
  518.     p->e.o.right = a2;
  519.     return p;
  520. }
  521.  
  522. struct enode *
  523. new_var(op, a1)
  524. struct ent_ptr a1;
  525. {
  526.     register struct enode *p;
  527.     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  528.     p->op = op;
  529.     p->e.v = a1;
  530.     return p;
  531. }
  532.  
  533. struct enode *
  534. new_range(op, a1)
  535. struct range_s a1;
  536. {
  537.     register struct enode *p;
  538.     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  539.     p->op = op;
  540.     p->e.r = a1;
  541.     return p;
  542. }
  543.  
  544. struct enode *
  545. new_const(op, a1)
  546. double a1;
  547. {
  548.     register struct enode *p;
  549.     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  550.     p->op = op;
  551.     p->e.k = a1;
  552.     return p;
  553. }
  554.  
  555. struct enode *
  556. new_str(s)
  557. char *s;
  558. {
  559.     register struct enode *p;
  560.  
  561.     p = (struct enode *) xmalloc ((unsigned)sizeof(struct enode));
  562.     p->op = O_SCONST;
  563.     p->e.s = s;
  564.     return(p);
  565. }
  566.  
  567. copy(dv1, dv2, v1, v2)
  568. struct ent *dv1, *dv2, *v1, *v2;
  569. {
  570.     int minsr, minsc;
  571.     int maxsr, maxsc;
  572.     int mindr, mindc;
  573.     int maxdr, maxdc;
  574.     int vr, vc;
  575.     int r, c;
  576.  
  577.     mindr = dv1->row;
  578.     mindc = dv1->col;
  579.     maxdr = dv2->row;
  580.     maxdc = dv2->col;
  581.     if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
  582.     if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
  583.     maxsr = v2->row;
  584.     maxsc = v2->col;
  585.     minsr = v1->row;
  586.     minsc = v1->col;
  587.     if (minsr>maxsr) r = maxsr, maxsr = minsr, minsr = r;
  588.     if (minsc>maxsc) c = maxsc, maxsc = minsc, minsc = c;
  589.     if (maxdr >= MAXROWS  || 
  590.            maxdc >= MAXCOLS) {
  591.     error ("The table can't be any bigger");
  592.     return;
  593.     }
  594.     erase_area(mindr, mindc, maxdr, maxdc);
  595.     if (minsr == maxsr && minsc == maxsc) {
  596.     /* Source is a single cell */
  597.     for(vr = mindr; vr <= maxdr; vr++)
  598.         for (vc = mindc; vc <= maxdc; vc++)
  599.         copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
  600.     } else if (minsr == maxsr) {
  601.     /* Source is a single row */
  602.     for (vr = mindr; vr <= maxdr; vr++)
  603.         copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
  604.     } else if (minsc == maxsc) {
  605.     /* Source is a single column */
  606.     for (vc = mindc; vc <= maxdc; vc++)
  607.         copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
  608.     } else {
  609.     /* Everything else */
  610.     copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
  611.     }
  612.     sync_refs();
  613. }
  614.  
  615. copyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
  616. int vr, vc, minsr, minsc, maxsr, maxsc;
  617. {
  618.     register struct ent *p;
  619.     register struct ent *n;
  620.     register int sr, sc;
  621.     register int dr, dc;
  622.  
  623.     for (dr=vr, sr=minsr; sr<=maxsr; sr++, dr++)
  624.     for (dc=vc, sc=minsc; sc<=maxsc; sc++, dc++) {
  625.         n = lookat (dr, dc);
  626.         (void) clearent(n);
  627.         if (p = tbl[sr][sc]) {
  628.         n -> v = p -> v;
  629.         n -> flags = p -> flags;
  630.         n -> expr = copye(p->expr, dr - sr, dc - sc);
  631.         n -> label = 0;
  632.         if (p -> label) {
  633.             n -> label = xmalloc ((unsigned)(strlen (p -> label) + 1));
  634.             (void) strcpy (n -> label, p -> label);
  635.         }
  636.         }
  637.     }
  638. }
  639.  
  640. eraser(v1, v2)
  641. struct ent *v1, *v2;
  642. {
  643.     FullUpdate++;
  644.     flush_saved();
  645.     erase_area(v1->row, v1->col, v2->row, v2->col);
  646.     sync_refs();
  647. }
  648.  
  649. moveto(v)
  650. struct ent *v;
  651. {
  652.     currow = v->row;
  653.     curcol = v->col;
  654. }
  655.  
  656. fill (v1, v2, start, inc)
  657. struct ent *v1, *v2;
  658. double start, inc;
  659. {
  660.     register r,c;
  661.     register struct ent *n;
  662.     int maxr, maxc;
  663.     int minr, minc;
  664.  
  665.     maxr = v2->row;
  666.     maxc = v2->col;
  667.     minr = v1->row;
  668.     minc = v1->col;
  669.     if (minr>maxr) r = maxr, maxr = minr, minr = r;
  670.     if (minc>maxc) c = maxc, maxc = minc, minc = c;
  671.     if (maxr >= MAXROWS) maxr = MAXROWS-1;
  672.     if (maxc >= MAXCOLS) maxc = MAXCOLS-1;
  673.     if (minr < 0) minr = 0;
  674.     if (minr < 0) minr = 0;
  675.  
  676.     FullUpdate++;
  677.     for (r = minr; r<=maxr; r++)
  678.     for (c = minc; c<=maxc; c++) {
  679.         n = lookat (r, c);
  680.         (void) clearent(n);
  681.         n->v = start;
  682.         start += inc;
  683.         n->flags |= (is_changed|is_valid);
  684.     }
  685. }
  686.  
  687. let (v, e)
  688. struct ent *v;
  689. struct enode *e;
  690. {
  691.     double val;
  692.  
  693.     exprerr = 0;
  694.     (void) signal(SIGFPE, eval_fpe);
  695.     if (setjmp(fpe_save)) {
  696.     error("Floating point exception %s", v_name(v->row, v->col));
  697.     val = 0.0;
  698.     } else {
  699.     val = eval(e);
  700.     }
  701.     (void) signal(SIGFPE, quit);
  702.     if (exprerr) {
  703.     efree(e);
  704.     return;
  705.     }
  706.     if (constant(e)) {
  707.     v->v = val;
  708.     if (!(v->flags & is_strexpr)) {
  709.             efree (v->expr);
  710.         v->expr = 0;
  711.     }
  712.     efree(e);
  713.         v->flags |= (is_changed|is_valid);
  714.         changed++;
  715.         modflg++;
  716.     return;
  717.     }
  718.     efree (v->expr);
  719.     v->expr = e;
  720.     v->flags |= (is_changed|is_valid);
  721.     v->flags &= ~is_strexpr;
  722.     changed++;
  723.     modflg++;
  724. }
  725.  
  726. slet (v, se, flushdir)
  727. struct ent *v;
  728. struct enode *se;
  729. int flushdir;
  730. {
  731.     char *p;
  732.  
  733.     exprerr = 0;
  734.     (void) signal(SIGFPE, eval_fpe);
  735.     if (setjmp(fpe_save)) {
  736.     error("Floating point exception %s", v_name(v->row, v->col));
  737.     p = "";
  738.     } else {
  739.     p = seval(se);
  740.     }
  741.     (void) signal(SIGFPE, quit);
  742.     if (exprerr) {
  743.     efree(se);
  744.     return;
  745.     }
  746.     if (constant(se)) {
  747.     label(v, p, flushdir);
  748.     if (p)
  749.         xfree(p);
  750.     efree(se);
  751.     if (v->flags & is_strexpr) {
  752.             efree (v->expr);
  753.         v->expr = 0;
  754.         v->flags &= ~is_strexpr;
  755.     }
  756.     return;
  757.     }
  758.     efree (v->expr);
  759.     v->expr = se;
  760.     v->flags |= (is_changed|is_strexpr);
  761.     if (flushdir<0) v->flags |= is_leftflush;
  762.     else v->flags &= ~is_leftflush;
  763.     FullUpdate++;
  764.     changed++;
  765.     modflg++;
  766. }
  767.  
  768. clearent (v)
  769. struct ent *v; {
  770.     if (!v)
  771.     return;
  772.     label(v,"",-1);
  773.     v->v = 0;
  774.     if (v->expr)
  775.     efree(v->expr);
  776.     v->expr = 0;
  777.     v->flags |= (is_changed);
  778.     v->flags &= ~(is_valid);
  779.     changed++;
  780.     modflg++;
  781. }
  782.  
  783. constant(e)
  784. register struct enode *e; {
  785.     return e==0 || e->op == O_CONST || e->op == O_SCONST
  786.     || (e->op != O_VAR
  787.      && (e->op&~0177) != O_REDUCE(0)
  788.      && constant (e->e.o.left)
  789.      && constant(e->e.o.right)
  790.      && e->op != NOW);
  791. }
  792.  
  793. efree (e)
  794. register struct enode *e; {
  795.     if (e) {
  796.     if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
  797.         && (e->op&~0177) != O_REDUCE(0)) {
  798.         efree(e->e.o.left);
  799.         efree(e->e.o.right);
  800.     }
  801.     if (e->op == O_SCONST && e->e.s)
  802.         xfree(e->e.s);
  803.     xfree ((char *)e);
  804.     }
  805. }
  806.  
  807. label (v, s, flushdir)
  808. register struct ent *v;
  809. register char *s; {
  810.     if (v) {
  811.     if (flushdir==0 && v->flags&is_valid) {
  812.         register struct ent *tv;
  813.         if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
  814.         v = tv, flushdir = 1;
  815.         else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
  816.         v = tv, flushdir = -1;
  817.         else flushdir = -1;
  818.     }
  819.     if (v->label) xfree((char *)(v->label));
  820.     if (s && s[0]) {
  821.         v->label = xmalloc ((unsigned)(strlen(s)+1));
  822.         (void) strcpy (v->label, s);
  823.     } else
  824.         v->label = 0;
  825.     if (flushdir<0) v->flags |= is_leftflush;
  826.     else v->flags &= ~is_leftflush;
  827.     FullUpdate++;
  828.     modflg++;
  829.     }
  830. }
  831.  
  832. decodev (v)
  833. struct ent_ptr v; 
  834. {
  835.     register struct range *r;
  836.  
  837.     if (!v.vp) (void)sprintf (line+linelim,"VAR?");
  838.     else if (r = find_range((char *)0, 0, v.vp, v.vp))
  839.         (void)sprintf(line+linelim, "%s", r->r_name);
  840.     else
  841.         (void)sprintf (line+linelim, "%s%s%s%d",
  842.             v.vf & FIX_COL ? "$" : "",
  843.             coltoa(v.vp->col),
  844.             v.vf & FIX_ROW ? "$" : "",
  845.             v.vp->row);
  846.     linelim += strlen (line+linelim);
  847. }
  848.  
  849. char *
  850. coltoa(col)
  851. int col;
  852. {
  853.     static char rname[3];
  854.     register char *p = rname;
  855.  
  856.     if (col > 25) {
  857.     *p++ = col/26 + 'A' - 1;
  858.     col %= 26;
  859.     }
  860.     *p++ = col+'A';
  861.     *p = 0;
  862.     return(rname);
  863. }
  864.  
  865. decompile(e, priority)
  866. register struct enode *e; {
  867.     register char *s;
  868.     if (e) {
  869.     int mypriority;
  870.     switch (e->op) {
  871.     default: mypriority = 99; break;
  872.     case '?': mypriority = 1; break;
  873.     case ':': mypriority = 2; break;
  874.     case '|': mypriority = 3; break;
  875.     case '&': mypriority = 4; break;
  876.     case '<': case '=': case '>': mypriority = 6; break;
  877.     case '+': case '-': case '#': mypriority = 8; break;
  878.     case '*': case '/': mypriority = 10; break;
  879.     case '^': mypriority = 12; break;
  880.     }
  881.     if (mypriority<priority) line[linelim++] = '(';
  882.     switch (e->op) {
  883.     case 'f':    { 
  884.                 for (s="fixed "; line[linelim++] = *s++;);
  885.                 linelim--;
  886.                 decompile (e->e.o.right, 30);
  887.                 break;
  888.             }
  889.     case 'm':    line[linelim++] = '-';
  890.             decompile (e->e.o.right, 30);
  891.             break;
  892.     case '~':    line[linelim++] = '~';
  893.             decompile (e->e.o.right, 30);
  894.             break;
  895.     case 'v':    decodev (e->e.v);
  896.             break;
  897.     case 'k':    (void)sprintf (line+linelim,"%.15g",e->e.k);
  898.             linelim += strlen (line+linelim);
  899.             break;
  900.     case '$':    (void)sprintf (line+linelim, "\"%s\"", e->e.s);
  901.             linelim += strlen(line+linelim);
  902.             break;
  903.     case O_REDUCE('+'):
  904.             s = "@sum("; goto more;
  905.     case O_REDUCE('*'):
  906.             s = "@prod("; goto more;
  907.     case O_REDUCE('s'):
  908.             s = "@stddev("; goto more;
  909.     case O_REDUCE(MAX):
  910.             s = "@max("; goto more;
  911.     case O_REDUCE(MIN):
  912.             s = "@min("; goto more;
  913.     case O_REDUCE('a'):
  914.             s = "@avg("; /* fall though to more; */
  915.     more:        {
  916.             struct range *r;
  917.  
  918.             for (; line[linelim++] = *s++;);
  919.             linelim--;
  920.             if (r = find_range((char *)0, 0, e->e.r.left.vp,
  921.                          e->e.r.right.vp)) {
  922.                 (void)sprintf(line+linelim, "%s", r->r_name);
  923.                 linelim += strlen(line+linelim);
  924.             } else {
  925.                 decodev (e->e.r.left);
  926.                 line[linelim++] = ':';
  927.                 decodev (e->e.r.right);
  928.             }
  929.             line[linelim++] = ')';
  930.             break;
  931.             }
  932.     case ACOS:    s = "@acos("; goto more1;
  933.     case ASIN:    s = "@asin("; goto more1;
  934.     case ATAN:    s = "@atan("; goto more1;
  935.     case CEIL:    s = "@ceil("; goto more1;
  936.     case COS:    s = "@cos("; goto more1;
  937.     case EXP:    s = "@exp("; goto more1;
  938.     case FABS:    s = "@fabs("; goto more1;
  939.     case FLOOR:    s = "@floor("; goto more1;
  940.     case HYPOT:    s = "@hypot("; goto more2;
  941.     case LOG:    s = "@ln("; goto more1;
  942.     case LOG10:    s = "@log("; goto more1;
  943.     case POW:    s = "@pow("; goto more2;
  944.     case SIN:    s = "@sin("; goto more1;
  945.     case SQRT:    s = "@sqrt("; goto more1;
  946.     case TAN:    s = "@tan("; goto more1;
  947.     case DTR:    s = "@dtr("; goto more1;
  948.     case RTD:    s = "@rtd("; goto more1;
  949.     case RND:    s = "@rnd("; goto more1;
  950.     case HOUR:    s = "@hour("; goto more1;
  951.     case MINUTE:    s = "@minute("; goto more1;
  952.     case SECOND:    s = "@second("; goto more1;
  953.     case MONTH:    s = "@month("; goto more1;
  954.     case DAY:    s = "@day("; goto more1;
  955.     case YEAR:    s = "@year("; goto more1;
  956.     case DATE:    s = "@date("; goto more1;
  957.     case STON:    s = "@ston("; goto more1;
  958.     case FMT:    s = "@fmt("; goto more2;
  959.     case EQS:    s = "@eqs("; goto more2;
  960.     more1:        for (; line[linelim++] = *s++;);
  961.             linelim--;
  962.             decompile (e->e.o.right, 0);
  963.             line[linelim++] = ')';
  964.             break;
  965.     more2:        for (; line[linelim++] = *s++;);
  966.             linelim--;
  967.             decompile (e->e.o.left, 0);
  968.             line[linelim++] = ',';
  969.             decompile (e->e.o.right, 0);
  970.             line[linelim++] = ')';
  971.             break;
  972.     case NOW:    s = "@now"; goto more0;
  973.     more0:        for (; line[linelim++] = *s++;);
  974.             linelim--;
  975.             break;
  976.     case SUBSTR:    s = "@substr(";
  977.             for (; line[linelim++] = *s++;);
  978.             linelim--;
  979.             decompile (e->e.o.left, 0);
  980.             line[linelim++] = ',';
  981.             decompile (e->e.o.right->e.o.left, 0);
  982.             line[linelim++] = ',';
  983.             decompile (e->e.o.right->e.o.right, 0);
  984.             line[linelim++] = ')';
  985.             break;
  986.  
  987.     default:    decompile (e->e.o.left, mypriority);
  988.             line[linelim++] = e->op;
  989.             decompile (e->e.o.right, mypriority+1);
  990.             break;
  991.     }
  992.     if (mypriority<priority) line[linelim++] = ')';
  993.     } else line[linelim++] = '?';
  994. }
  995.  
  996. editv (row, col) {
  997.     register struct ent *p;
  998.  
  999.     p = lookat (row, col);
  1000.     (void)sprintf (line, "let %s = ", v_name(row, col));
  1001.     linelim = strlen(line);
  1002.     if (p->flags & is_strexpr || p->expr == 0) {
  1003.     (void)sprintf (line+linelim, "%.15g", p->v);
  1004.     linelim += strlen (line+linelim);
  1005.     } else {
  1006.         editexp(row,col);
  1007.     }
  1008. }
  1009.  
  1010. editexp(row,col) {
  1011.     register struct ent *p;
  1012.  
  1013.     p = lookat (row, col);
  1014.     decompile (p->expr, 0);
  1015.     line[linelim] = 0;
  1016. }
  1017.  
  1018. edits (row, col) {
  1019.     register struct ent *p;
  1020.  
  1021.     p = lookat (row, col);
  1022.     (void)sprintf (line, "%sstring %s = ",
  1023.             ((p->flags&is_leftflush) ? "left" : "right"),
  1024.             v_name(row, col));
  1025.     linelim = strlen(line);
  1026.     if (p->flags & is_strexpr && p->expr) {
  1027.     editexp(row, col);
  1028.     } else {
  1029.         (void)sprintf (line+linelim, "\"%s\"", p->label);
  1030.         linelim += strlen (line+linelim);
  1031.     }
  1032. }
  1033.  
  1034. printfile (fname, r0, c0, rn, cn)
  1035. char *fname;
  1036. {
  1037.     FILE *f;
  1038.     char pline[1000];
  1039.     int plinelim;
  1040.     int pid;
  1041.     int fieldlen, nextcol;
  1042.     register row, col;
  1043.     register struct ent **p;
  1044.     char ch, lin[100];
  1045.  
  1046.     if (strcmp(fname, curfile) == 0) {
  1047.     (void) move (0, 0);
  1048.     (void) clrtoeol ();
  1049.     (void) sprintf (lin,
  1050.         "Confirm that you want to destroy the data base: (y,n)");
  1051.     (void) addstr (lin);
  1052.     (void) refresh();
  1053.     ch = nmgetch();
  1054.     if (ch != 'y' && ch != 'Y') 
  1055.         return;
  1056.     }
  1057.  
  1058.     f = openout(fname, &pid);
  1059.  
  1060.     if (f==0) {
  1061.     error ("Can't create %s", fname);
  1062.     return;
  1063.     }
  1064.     for (row=r0;row<=rn; row++) {
  1065.     register c = 0;
  1066.     pline[plinelim=0] = '\0';
  1067.     for (p = &tbl[row][col=c0]; col<=cn;
  1068.             p += nextcol-col, col = nextcol, c += fieldlen) {
  1069.  
  1070.         fieldlen = fwidth[col];
  1071.         nextcol = col+1;
  1072.         if (*p) {
  1073.         char *s;
  1074.  
  1075.         while (plinelim<c) pline[plinelim++] = ' ';
  1076.         plinelim = c;
  1077.         if ((*p)->flags&is_valid) {
  1078.             (void)sprintf (pline+plinelim,"%*.*f",fwidth[col],
  1079.                                         precision[col], (*p)->v);
  1080.             plinelim += strlen (pline+plinelim);
  1081.         }
  1082.         if (s = (*p)->label) {
  1083.             int slen;
  1084.             char *start, *last;
  1085.             register char *fp;
  1086.             struct ent *nc;
  1087.  
  1088.             /* Figure out if the label slops over to a blank field */
  1089.             slen = strlen(s);
  1090.             while (slen > fieldlen && nextcol <= cn &&
  1091.                 !((nc = lookat(row,nextcol))->flags & is_valid) &&
  1092.                 !(nc->label)) {
  1093.             
  1094.             fieldlen += fwidth[nextcol];
  1095.             nextcol++;
  1096.             }
  1097.             if (slen > fieldlen)
  1098.             slen = fieldlen;
  1099.             
  1100.             /* Now justify and print */
  1101.             start = (*p)->flags & is_leftflush ? pline + c
  1102.                     : pline + c + fieldlen - slen;
  1103.             last = pline + c + fieldlen;
  1104.             fp = plinelim < c ? pline + plinelim : pline + c;
  1105.             while (fp < start)
  1106.             *fp++ = ' ';
  1107.             while (slen--)
  1108.             *fp++ = *s++;
  1109.             if (!((*p)->flags & is_valid) || fieldlen != fwidth[col])
  1110.             while(fp < last)
  1111.                 *fp++ = ' ';
  1112.             if (plinelim < fp - pline)
  1113.             plinelim = fp - pline;
  1114.         }
  1115.         }
  1116.     }
  1117.     (void) fprintf (f,"%.*s\n",plinelim,pline);
  1118.     }
  1119.  
  1120.     closeout(f, pid);
  1121. }
  1122.  
  1123. tblprintfile (fname, r0, c0, rn, cn)
  1124. char *fname;
  1125. {
  1126.     FILE *f;
  1127.     char pline[1000];
  1128.     int pid;
  1129.     register row, col;
  1130.     register struct ent **p;
  1131.     char coldelim = DEFCOLDELIM;
  1132.     char ch, lin[100];
  1133.  
  1134.     if (strcmp(fname, curfile) == 0) {
  1135.     (void) move (0, 0);
  1136.     (void) clrtoeol ();
  1137.     (void) sprintf (lin,
  1138.         "Confirm that you want to destroy the data base: (y,n)");
  1139.     (void) addstr (lin);
  1140.     (void) refresh();
  1141.     ch = nmgetch();
  1142.     if (ch != 'y' && ch != 'Y') 
  1143.         return;
  1144.     }
  1145.  
  1146.     f = openout(fname, &pid);
  1147.  
  1148.     if (f==0) {
  1149.     error ("Can't create %s", fname);
  1150.     return;
  1151.     }
  1152.     for (row=r0; row<=rn; row++) {
  1153.     for (p = &tbl[row][col=c0]; col<=cn; col++, p++) {
  1154.         if (*p) {
  1155.         char *s;
  1156.         if ((*p)->flags&is_valid) {
  1157.             (void) fprintf (f,"%.*f",precision[col],
  1158.                 (*p)->v);
  1159.         }
  1160.         if (s = (*p)->label) {
  1161.                 (void) fprintf (f,"%s",s);
  1162.         }
  1163.         }
  1164.         (void) fprintf(f,"%c",coldelim);
  1165.     }
  1166.     (void) fprintf (f,"\n",pline);
  1167.     }
  1168.  
  1169.     closeout(f, pid);
  1170. }
  1171.  
  1172. struct enode *
  1173. copye (e, Rdelta, Cdelta)
  1174. register struct enode *e; {
  1175.     register struct enode *ret;
  1176.     if (e==0) ret = 0;
  1177.     else {
  1178.     ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
  1179.     ret->op = e->op;
  1180.     switch (ret->op) {
  1181.     case 'v':
  1182.         {
  1183.             int newrow, newcol;
  1184.             newrow=e->e.v.vf & FIX_ROW ? e->e.v.vp->row :
  1185.                          e->e.v.vp->row+Rdelta;
  1186.             newcol=e->e.v.vf & FIX_COL ? e->e.v.vp->col :
  1187.                          e->e.v.vp->col+Cdelta;
  1188.             ret->e.v.vp = lookat (newrow, newcol);
  1189.             ret->e.v.vf = e->e.v.vf;
  1190.             break;
  1191.         }
  1192.     case 'k':
  1193.         ret->e.k = e->e.k;
  1194.         break;
  1195.     case 'f':
  1196.         ret->e.o.right = copye (e->e.o.right,0,0);
  1197.         ret->e.o.left = 0;
  1198.          break;
  1199.     case '$':
  1200.         ret->e.s = xmalloc((unsigned) strlen(e->e.s)+1);
  1201.         (void) strcpy(ret->e.s, e->e.s);
  1202.         break;
  1203.      case O_REDUCE('+'):
  1204.      case O_REDUCE('*'):
  1205.      case O_REDUCE('a'):
  1206.      case O_REDUCE('s'):
  1207.      case O_REDUCE(MAX):
  1208.      case O_REDUCE(MIN):
  1209.         {
  1210.             int newrow, newcol;
  1211.             newrow=e->e.r.left.vf & FIX_ROW ?e->e.r.left.vp->row :
  1212.                              e->e.r.left.vp->row+Rdelta;
  1213.             newcol=e->e.r.left.vf & FIX_COL ?e->e.r.left.vp->col :
  1214.                              e->e.r.left.vp->col+Cdelta;
  1215.             ret->e.r.left.vp = lookat (newrow, newcol);
  1216.             ret->e.r.left.vf = e->e.r.left.vf;
  1217.             newrow=e->e.r.right.vf & FIX_ROW ?e->e.r.right.vp->row :
  1218.                             e->e.r.right.vp->row+Rdelta;
  1219.             newcol=e->e.r.right.vf & FIX_COL ?e->e.r.right.vp->col :
  1220.                             e->e.r.right.vp->col+Cdelta;
  1221.             ret->e.r.right.vp = lookat (newrow, newcol);
  1222.             ret->e.r.right.vf = e->e.r.right.vf;
  1223.             break;
  1224.         }
  1225.     default:
  1226.         ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
  1227.         ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
  1228.         break;
  1229.     }
  1230.     }
  1231.     return ret;
  1232. }
  1233.  
  1234. /*
  1235.  * sync_refs and syncref are used to remove references to
  1236.  * deleted struct ents.  Note that the deleted structure must still
  1237.  * be hanging around before the call, but not referenced by an entry
  1238.  * in tbl.  Thus the free_ent, fix_ent calls in sc.c
  1239.  */
  1240.  
  1241. sync_refs () {
  1242.     register i,j;
  1243.     register struct ent *p;
  1244.     sync_ranges();
  1245.     for (i=0; i<=maxrow; i++)
  1246.     for (j=0; j<=maxcol; j++)
  1247.         if ((p=tbl[i][j]) && p->expr)
  1248.         syncref(p->expr);
  1249. }
  1250.  
  1251.  
  1252. syncref(e)
  1253. register struct enode *e;
  1254. {
  1255.     if (e==0)
  1256.     return;
  1257.     else {
  1258.     switch (e->op) {
  1259.     case 'v':
  1260.         e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col);
  1261.         break;
  1262.     case 'k':
  1263.         break;
  1264.     case '$':
  1265.         break;
  1266.      case O_REDUCE('+'):
  1267.      case O_REDUCE('*'):
  1268.      case O_REDUCE('a'):
  1269.      case O_REDUCE('s'):
  1270.      case O_REDUCE(MAX):
  1271.      case O_REDUCE(MIN):
  1272.          e->e.r.right.vp = lookat ( e->e.r.right.vp->row,
  1273.                                            e->e.r.right.vp->col);
  1274.          e->e.r.left.vp = lookat ( e->e.r.left.vp->row,
  1275.                                           e->e.r.left.vp->col);
  1276.         break;
  1277.     default:
  1278.         syncref(e->e.o.right);
  1279.         syncref(e->e.o.left);
  1280.         break;
  1281.     }
  1282.     }
  1283. }
  1284.  
  1285. hiderow(arg)
  1286. {
  1287.     register int r1;
  1288.     register int r2;
  1289.  
  1290.     r1 = currow;
  1291.     r2 = r1 + arg - 1;
  1292.     if (r1 < 0 || r1 > r2) {
  1293.     error("Invalid Range");
  1294.     return;
  1295.     }
  1296.     if (r2 > MAXROWS-2) {
  1297.     error("You can't hide the last row");
  1298.     return;
  1299.     }
  1300.     FullUpdate++;
  1301.     while (r1 <= r2)
  1302.     row_hidden[r1++] = 1;
  1303. }
  1304.  
  1305. hidecol(arg)
  1306. {
  1307.     register int c1;
  1308.     register int c2;
  1309.  
  1310.     c1 = curcol;
  1311.     c2 = c1 + arg - 1;
  1312.     if (c1 < 0 || c1 > c2) {
  1313.     error("Invalid Range");
  1314.     return;
  1315.     }
  1316.     if (c2 > MAXCOLS-2) {
  1317.     error("You can't hide the last col");
  1318.     return;
  1319.     }
  1320.     FullUpdate++;
  1321.     while (c1 <= c2)
  1322.     col_hidden[c1++] = 1;
  1323. }
  1324.  
  1325. showrow(r1, r2)
  1326. {
  1327.     if (r1 < 0 || r1 > r2) {
  1328.     error("Invalid Range");
  1329.     return;
  1330.     }
  1331.     if (r2 > MAXROWS-1) {
  1332.     r2 = MAXROWS-1;
  1333.     }
  1334.     FullUpdate++;
  1335.     while (r1 <= r2)
  1336.     row_hidden[r1++] = 0;
  1337. }
  1338.  
  1339. showcol(c1, c2)
  1340. {
  1341.     if (c1 < 0 || c1 > c2) {
  1342.     error("Invalid Range");
  1343.     return;
  1344.     }
  1345.     if (c2 > MAXCOLS-1) {
  1346.     c2 = MAXCOLS-1;
  1347.     }
  1348.     FullUpdate++;
  1349.     while (c1 <= c2)
  1350.     col_hidden[c1++] = 0;
  1351. }
  1352.  
  1353. /* Open the output file, setting up a pipe if needed */
  1354.  
  1355. FILE *
  1356. openout(fname, rpid)
  1357. char *fname;
  1358. int *rpid;
  1359. {
  1360.     int pipefd[2];
  1361.     int pid;
  1362.     FILE *f;
  1363.  
  1364.     while (*fname && (*fname == ' '))  /* Skip leading blanks */
  1365.     fname++;
  1366.  
  1367.     if (*fname != '|') {        /* Open file if not pipe */
  1368.     *rpid = 0;
  1369.     return(fopen(fname, "w"));
  1370.     }
  1371.  
  1372.     fname++;                /* Skip | */
  1373.     if ( pipe (pipefd) < 0) {
  1374.     error("Can't make pipe to child");
  1375.     *rpid = 0;
  1376.     return(0);
  1377.     }
  1378.  
  1379.     deraw();
  1380.     if ((pid=fork()) == 0)              /* if child  */
  1381.     {
  1382.     (void) close (0);              /* close stdin */
  1383.     (void) close (pipefd[1]);
  1384.     (void) dup (pipefd[0]);          /* connect to pipe input */
  1385.     (void) execl ("/bin/sh", "sh", "-c", fname, 0);
  1386.     exit (-127);
  1387.     }
  1388.     else                  /* else parent */
  1389.     {
  1390.     *rpid = pid;
  1391.     f = fdopen (pipefd[1], "w");
  1392.     if (f == 0)
  1393.     {
  1394.         (void) kill (pid, -9);
  1395.         error ("Can't fdopen output");
  1396.         (void) close (pipefd[1]);
  1397.         *rpid = 0;
  1398.         return(0);
  1399.     }
  1400.     }
  1401.     return(f);
  1402. }
  1403.  
  1404. closeout(f, pid)
  1405. FILE *f;
  1406. int pid;
  1407. {
  1408.     int temp;
  1409.  
  1410.     (void) fclose (f);
  1411.     if (pid) {
  1412.          while (pid != wait(&temp)) /**/;
  1413.      (void) printf("Press <return> to continue");
  1414.      (void) fflush(stdout);
  1415.      (void) nmgetch();
  1416.      goraw();
  1417.     }
  1418. }
  1419.